
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using Vanara.PInvoke;
using static Vanara.PInvoke.AdvApi32;
using static Vanara.PInvoke.Kernel32;

namespace GPDWin4GameBarPowerBackend {
	public class ProcessAsUser
	{
		
		
        public static System.Diagnostics.Process Start(string commandLine, bool showWindow)
        {
            SafeHTOKEN hToken;
            SafeHTOKEN hTokenDup;
            const CREATE_PROCESS CREATE_PROCESS_FLAGS = 

            CREATE_PROCESS.CREATE_NEW_CONSOLE | CREATE_PROCESS.NORMAL_PRIORITY_CLASS | CREATE_PROCESS.CREATE_UNICODE_ENVIRONMENT;

            if(!OpenProcessToken(GetCurrentProcess(),TokenAccess.TOKEN_ALL_ACCESS,out hToken))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            var sa = new SECURITY_ATTRIBUTES();
            sa.bInheritHandle = true;

            if(!DuplicateTokenEx(hToken,TokenAccess.TOKEN_ALL_ACCESS,sa,SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,TOKEN_TYPE.TokenPrimary,out hTokenDup))
            {
                var err = Marshal.GetLastWin32Error();
                CloseHandle((HTOKEN)hToken);
                throw new Win32Exception(err);
            }


            var si = new STARTUPINFO();
            si.cb = (uint)Marshal.SizeOf(si);
            si.lpDesktop = "WinSta0\\Default";
            if(!showWindow)
            {
                si.dwFlags = STARTF.STARTF_USESHOWWINDOW;
                si.wShowWindow = 0;
            }

            var dwSessionId = WTSGetActiveConsoleSessionId();

            string[] pEnv = null;
            IntPtr malloc = Marshal.AllocHGlobal(sizeof(uint));
            Marshal.StructureToPtr(dwSessionId, malloc, false);
            if(!SetTokenInformation(hTokenDup,TOKEN_INFORMATION_CLASS.TokenSessionId, malloc, sizeof(uint)))
            {
                var error = Marshal.GetLastWin32Error(); 
                CloseHandle((HTOKEN)hToken);
                CloseHandle((HTOKEN)hTokenDup);
                Marshal.FreeHGlobal(malloc);
                throw new Win32Exception(error);
            }
            Marshal.FreeHGlobal(malloc);

            if(!UserEnv.CreateEnvironmentBlock(out pEnv, hTokenDup, false))
            {
                var error = Marshal.GetLastWin32Error();
                CloseHandle((HTOKEN)hToken);
                CloseHandle((HTOKEN)hTokenDup);
                throw new Win32Exception(error);
            }

            SafePROCESS_INFORMATION pro;

            if(!(CreateProcessAsUser(hTokenDup,null,new System.Text.StringBuilder(commandLine),sa,sa,true,CREATE_PROCESS_FLAGS,pEnv,null,si,out pro)))
            {
                var error = Marshal.GetLastWin32Error();
                CloseHandle((HTOKEN)hToken);
                CloseHandle((HTOKEN)hTokenDup);
                throw new Win32Exception(error);
            }

            CloseHandle((HTOKEN)hToken);
            CloseHandle((HTOKEN)hTokenDup);
            return System.Diagnostics.Process.GetProcessById((int)pro.dwProcessId);
        }
        
	}
}
